const crypto = require('crypto');
const fs = require('fs'); // Added fs module
const { log } = require('../config/logging');

// Helper function to get secret from environment variable or file
function getSecret(baseVarName) {
  const directValue = process.env[baseVarName];
  const fileVarName = `${baseVarName}_FILE`;
  const filePath = process.env[fileVarName];

  if (directValue) {
    log('debug', `Using direct environment variable for ${baseVarName}`);
    return directValue;
  } else if (filePath) {
    log('debug', `Reading secret for ${baseVarName} from file: ${filePath}`);
    try {
      return fs.readFileSync(filePath, 'utf8').trim();
    } catch (error) {
      log('error', `Failed to read secret from file ${filePath} for ${baseVarName}: ${error.message}`);
      process.exit(1);
    }
  } else {
    log('error', `${baseVarName} or ${fileVarName} is not set in environment variables.`);
    process.exit(1);
  }
}

const ENCRYPTION_KEY_RAW = getSecret('SPARKY_FITNESS_API_ENCRYPTION_KEY');
const JWT_SECRET_RAW = getSecret('JWT_SECRET');

// The key generated by `openssl rand -base64 32` is 44 characters long.
// The key generated by `node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"` is 64 characters long.
if (ENCRYPTION_KEY_RAW.length !== 64 && ENCRYPTION_KEY_RAW.length !== 44) {
  log('error', `Encryption key (SPARKY_FITNESS_API_ENCRYPTION_KEY) has an invalid length. Expected 64 hex characters or 44 Base64 characters. Update your environment variable and try again.`);
  process.exit(1);
}

if (JWT_SECRET_RAW.length !== 64 && JWT_SECRET_RAW.length !== 44) {
  log('error', `JWT authentication key (JWT_SECRET) has an invalid length. Expected 64 hex characters or 44 Base64 characters. Update your environment variable and try again.`);
  process.exit(1);
}

const ENCRYPTION_KEY = ENCRYPTION_KEY_RAW.length === 44 ? Buffer.from(ENCRYPTION_KEY_RAW, 'base64').toString('hex') : ENCRYPTION_KEY_RAW;
const JWT_SECRET = JWT_SECRET_RAW.length === 44 ? Buffer.from(JWT_SECRET_RAW, 'base64').toString('hex') : JWT_SECRET_RAW;

// Utility functions for encryption and decryption
async function encrypt(text, key) {
  log('debug', `Encrypting text with key of length: ${key.length}`);
  if (!text) {
    return { encryptedText: null, iv: null, tag: null };
  }
  const iv = crypto.randomBytes(12); // GCM recommended IV size is 12 bytes
  const cipher = crypto.createCipheriv('aes-256-gcm', Buffer.from(key, 'hex'), iv);
  let encrypted = cipher.update(text, 'utf8', 'base64');
  encrypted += cipher.final('base64');
  const tag = cipher.getAuthTag().toString('base64');
  return { encryptedText: encrypted, iv: iv.toString('base64'), tag: tag };
}

async function decrypt(encryptedText, ivString, tagString, key) {
  log('debug', `Decrypting text with key of length: ${key.length}`);
  if (!encryptedText || !ivString || !tagString) {
    log('warn', 'Attempted to decrypt null or incomplete data. Returning null.');
    return null;
  }
  const iv = Buffer.from(ivString, 'base64');
  const tag = Buffer.from(tagString, 'base64');
  const decipher = crypto.createDecipheriv('aes-256-gcm', Buffer.from(key, 'hex'), iv);
  decipher.setAuthTag(tag);
  let decrypted = decipher.update(encryptedText, 'base64', 'utf8');
  decrypted += decipher.final('utf8');
  return decrypted;
}

module.exports = {
  encrypt,
  decrypt,
  ENCRYPTION_KEY,
  JWT_SECRET
};